package com.borya.task;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.internal.util.StringUtils;
import com.borya.constant.RedisConstant;
import com.borya.dao.*;
import com.borya.framework.core.ServerBeanFactory;
import com.borya.model.db.MerchantInfoFill;
import com.borya.model.db.MerchantPerfectionRecordInfo;
import com.borya.model.db.Message;
import com.borya.model.db.RegistOrderInfo;
import com.borya.service.server.UserService;
import com.borya.task.model.RespAudit;
import com.borya.util.Constant;
import com.borya.util.Constant.RegisterAuditOrderStatus;
import com.borya.util.DateUtils;
import com.borya.util.StringUtil;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import java.util.concurrent.*;
import java.util.concurrent.locks.LockSupport;

public class AutomaticAudittask{
	
	private final int FIXED_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2;
	private final int BLOCKING_QUEUE_SIZE = 128 * 1024;
	
	private volatile boolean isRunning = false;
	private Logger log = LogManager.getLogger(getClass());
	private ExecutorService bossExecutor = Executors.newSingleThreadExecutor();
	private ExecutorService workerProcess;
	private ExecutorService workerReq;

	private UserDAO userDAO;
	private RegistOrderInfoDAO registOrderInfoDAO;
	private UserService userService;
	private MerchantFillServiceDAO merchantFillServiceDAO;
	private MerchantDAO merchantDAO;
	private MessageDAO messageDAO;
    private MerchantPerfectionServiceDAO merchantPerfectionServiceDAO;
	
	private AutomaticAudittask() {
		System.err.println("Initializing audit order service...");
		workerProcess = new ThreadPoolExecutor(FIXED_POOL_SIZE, FIXED_POOL_SIZE, 1, TimeUnit.MINUTES,
				new ArrayBlockingQueue<Runnable>(BLOCKING_QUEUE_SIZE));
		workerReq = new ThreadPoolExecutor(FIXED_POOL_SIZE, FIXED_POOL_SIZE, 1, TimeUnit.MINUTES,
				new ArrayBlockingQueue<Runnable>(BLOCKING_QUEUE_SIZE));
	}

	public void start() {
		isRunning = true;
		bossExecutor.execute(()-> {
			LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
			while (isRunning) {
				try {
					userDAO = (UserDAO) ServerBeanFactory.getInstance().getBeanByName("userDAOImpl");
					registOrderInfoDAO = (RegistOrderInfoDAO) ServerBeanFactory.getInstance().getBeanByName("registOrderInfoDAO");
					merchantFillServiceDAO = (MerchantFillServiceDAO)ServerBeanFactory.getInstance().getBeanByName("merchantFillServiceDAO");
					merchantDAO = (MerchantDAO)ServerBeanFactory.getInstance().getBeanByName("merchantDAO");
					userService = (UserService) ServerBeanFactory.getInstance().getBeanByName("server_userServiceImpl");
					messageDAO = (MessageDAO) ServerBeanFactory.getInstance().getBeanByName("messageDAO");
                    merchantPerfectionServiceDAO = (MerchantPerfectionServiceDAO)ServerBeanFactory.getInstance().getBeanByName("merchantPerfectionServiceDAO");
					process();
				} catch (Exception e) {
					log.error("Catch exception on poping message from queue!", e);
					LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(16));
				}
			}
		});
	}

	private void process() throws Exception {
		final String respMessage = popMessage(RedisConstant.MQ_AUDITED_ORDER);

		if (respMessage == null) {
			LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
			return;
		}
		RespAudit resp = JSONObject.parseObject(respMessage, RespAudit.class);
		workerProcess.execute(()-> {
			try {
				if(log.isDebugEnabled()){
					log.debug("RespAudit:"+resp);
				}
				handle(resp);
			} catch (Exception e) {
				log.error("Catch exception on handling message: " + resp, e);
			}
		});
	}

	private void handle(RespAudit resp) throws Exception {
		String orderId = resp.getOrderId();
		String result = resp.getResult();
		String desc = resp.getDesc();
		int source = resp.getSource();
		long curTime = System.currentTimeMillis();
		String gztCheckResult = resp.getGztCheckResult();
		if (StringUtils.isEmpty(result)) {
			log.error("自动审核系统错误，评分错误，result不能为空或null");
			return;
		}
		if (!"1,2,3,4".contains(result)) {
			log.error("自动审核系统错误，评分错误，结果不在1,2,3,4之间。result:" + result);
			return;
		}
		if( 1 != source){
			log.error("自动审核系统错误，评分错误，来源不是卡盟APP。source:" + source);
			return;
		}
		
		//商户实名补录订单
		if(orderId.startsWith(Constant.MERCHANT_ORDER_PREFIX)){
			//商户实名补录
			MerchantInfoFill infoFill = merchantFillServiceDAO.getByOrderId(orderId);
			infoFill.setAutoAuditDesc(desc);
			switch (Integer.parseInt(result)) {
			case 2:
				/**拒绝**/
				StringBuilder content = new StringBuilder(256);
				content.append("尊敬的用户,您的绑定设备申请于");
				content.append(DateUtils.format(curTime, "yyyy-MM-dd HH:mm:ss"));
				content.append("被拒绝，原因是：");
				content.append(desc);
				content.append("。请按照要求，重新申请绑定设备。");
				saveMsg(infoFill.getUserId(), 244, curTime, content.toString());
				
				infoFill.setAutoAuditDesc(desc);
				infoFill.setOrderStatus(RegisterAuditOrderStatus.FAILED);
				merchantFillServiceDAO.updateStatus(infoFill);
				merchantDAO.updateStatus(infoFill.getMerchantId(), RegisterAuditOrderStatus.FAILED);
				break;
			default:
				//1通过2拒绝3待分配4已分配5等待自动审核6复审通过
				waitAllot(infoFill);
				break;
			}
        } else if (orderId.startsWith(Constant.MERCHANT_PERFECTION_PREFIX)) {
            // 为商户资料完善订单
            MerchantPerfectionRecordInfo recordInfo = merchantPerfectionServiceDAO.getByOrderId(orderId);
            recordInfo.setAutoAuditDesc(desc);
            recordInfo.setAuditTime(curTime);
            recordInfo.setUpdateTime(curTime);
            recordInfo.setAuditCustomer("自动审核");
            recordInfo.setGztRheck(gztCheckResult);
            recordInfo.setStatus(3);
            StringBuilder content = new StringBuilder(256);
            switch (Integer.parseInt(result)) {
                case 1:
                    /**成功**/
                    recordInfo.setResult(1);
                    content.append("尊敬的用户,您的资料完善订单已经于");
                    content.append(DateUtils.format(curTime, "yyyy-MM-dd HH:mm:ss"));
                    content.append("审核通过。");
                    saveMsg(recordInfo.getMerchantId(), 244, curTime, content.toString());
                    break;
                case 2:
                    /**拒绝**/
                    recordInfo.setResult(2);
                    content.append("尊敬的用户,您的资料完善订单已经于");
                    content.append(DateUtils.format(curTime, "yyyy-MM-dd HH:mm:ss"));
                    content.append("被拒绝，原因是：");
                    content.append(desc);
                    content.append("。请按照要求，重新申请提交完善资料。");
                    saveMsg(recordInfo.getMerchantId(), 244, curTime, content.toString());
                    break;
                default:
                    log.error("自动审核系统错误，评分错误，结果不在1,2,3,4之间。result:" + result);
                    return;
            }
            boolean updRecordInfo = merchantPerfectionServiceDAO.updateMerchantPerfection(recordInfo);
            log.info("资料完善身份信息预审修改DB:orderId=" + orderId + (updRecordInfo ? "成功" : "失败"));
        } else if (orderId.startsWith(Constant.ADD_JOB_NUM)) {
            // 添加子工号订单
            //int detailType = resp.getDetailType();
            updateResult(orderId, result, desc, gztCheckResult);
        } else {
            RegistOrderInfo orderInfo = registOrderInfoDAO.getToAuditOrderInfo(orderId);
            orderInfo.setAutoAuditDesc(desc);
            orderInfo.setAuditTime(curTime);
            orderInfo.setCustomer("自动审核");
            orderInfo.setGztCheck(gztCheckResult);
            switch (Integer.parseInt(result)) {
                case 1:
                    /**成功**/
                    orderInfo.setOrderStatus(1);
                    orderInfo.setAuditType(3);
                    orderInfo.setRemarks("自动审核通过");
                    break;
                case 2:
                    /**拒绝**/
                    orderInfo.setOrderStatus(2);
                    orderInfo.setAuditType(3);
                    orderInfo.setRemarks(desc);

                    StringBuilder content = new StringBuilder(256);
                    content.append("尊敬的用户,您的绑定设备申请于");
                    content.append(DateUtils.format(curTime, "yyyy-MM-dd HH:mm:ss"));
                    content.append("被拒绝，原因是：");
                    content.append(desc);
                    content.append("。请按照要求，重新申请绑定设备。");
//				saveMsg(orderInfo.getUserId(), 244, curTime, content.toString());

                    break;
                case 3:
                    /**转实时审核**/
                    orderInfo.setOrderStatus(3);
                    orderInfo.setAuditType(1);
                    orderInfo.setRemarks(desc);
                    break;
                case 4:
                    /**转事后审核**/
                    orderInfo.setOrderStatus(3);
                    orderInfo.setAuditType(2);
                    orderInfo.setRemarks(desc);
                    break;
                default:
                    log.error("自动审核系统错误，评分错误，结果不在1,2,3,4之间。result:" + result);
                    return;
            }
            boolean updAudit = userDAO.auditOrder(orderInfo);
            log.info("自动审核修改DB:orderId=" + orderId + (updAudit ? "成功" : "失败"));
            if (updAudit && !"3".equals(result)) {
                sentResult(orderInfo, result, desc);
            }
        }
	}
	
	/**
	 * 失败以外的状态更改为(人工)进行中
	 * @param infoFill
	 */
	private void waitAllot(MerchantInfoFill infoFill){
		infoFill.setOrderStatus(RegisterAuditOrderStatus.WAIT_ALLOT);
		merchantFillServiceDAO.updateStatus(infoFill);
		merchantDAO.updateStatus(infoFill.getMerchantId(), 4);//进行中
	}
	
	private String popMessage(String queue) {
		return userDAO.redis_lpop(queue);
	}

	private Long pushMessage(String queue, String message) {
		return userDAO.redis_rpush(queue, message);
	}

	public void execute(String respInfo) {
		workerReq.execute(()-> {
			log.info("ReqAmsMSG:"+respInfo);
			pushMessage(RedisConstant.MQ_AUDITING_ORDER, respInfo);
		});
	}

	private static class Holder {
		private static final AutomaticAudittask INSTANCE = new AutomaticAudittask();
	}

	public static final AutomaticAudittask getInstance() {
		return Holder.INSTANCE;
	}

    private void updateResult(String orderId, String result, String desc, String gztCheckResult) {
        JSONObject json = new JSONObject();
        json.put("orderId", orderId);
        json.put("result", result);
        json.put("desc", desc);
        json.put("gztCheckResult", gztCheckResult);
        json.put("auditType", "1"); //  审核类型：1自动审核，2人工审核
        //json.put("detailType", detailType);
        userService.addJobNumAuditBack(json);
    }

	private void sentResult(RegistOrderInfo orderInfo, String result, String remarks){
		JSONObject json = new JSONObject();
		json.put("orderId", orderInfo.getOrderId());
		json.put("dealerId", orderInfo.getDealerId());
		json.put("devMac", orderInfo.getDevMac());
		json.put("beforeStatus", orderInfo.getBeforeStatus());
		json.put("result", result);
		json.put("remarks", remarks);
		json.put("operationType", orderInfo.getOperationType());
		userService.registAudited(json);
	}
	
	
	private void saveMsg(String userId,int type,long time, String msgStr){
		log.debug("send msg to:"+userId);
		Message msg = new Message();
		msg.setMsgId("system_"+StringUtil.randomString(8));
		msg.setMsgType(Message.MessageType.BUSINESS);
		msg.setSender("system");
		msg.setReceiver(userId);
		msg.setCreatTime(time);
		msg.setExpTime(time + 30 * 24 * 60 *60 *1000);
		StringBuilder content = new StringBuilder(256);
		content.append("{");
		content.append("\"type\":").append(type);
		content.append(",\"title\": \"商户绑定设备结果通知\"");
		content.append(",\"annex\":[]");
		content.append(",\"content\":\"");
		content.append(msgStr);
		content.append("\"");
		content.append(",\"redirectUrl\":\"\"");
		content.append("}");
		msg.setContent(content.toString());
		messageDAO.save(msg);
	}
}
